﻿/*
 * Erstellt mit SharpDevelop.
 * Benutzer: Kai Patrick
 * Datum: 29.03.2008
 * Zeit: 10:45
 * 
 * Sie können diese Vorlage unter Extras > Optionen > Codeerstellung > Standardheader ändern.
 */

using System;

namespace Gamadus.Engine
{
	public class GmlVar
	{
		private object value;
		
		public object Value
		{
			get
			{
				return value;
			}
		}
		
		public string GetString()
		{
			if(!(value is string))
				throw new ArgumentException("Value is not a string");
			return (string)value;
		}
		
		public real GetReal()
		{
			if(!(value is real))
				throw new ArgumentException("Value is not a real");
			return (real)value;
		}
		
		public double GetDouble()
		{
			if(!(value is real))
				throw new ArgumentException("Value is not a real");
			return (double)(real)value;
		}
		
		public GmlVar(string value)
		{
			this.value = value;
		}
		
		public GmlVar(real value)
		{
			this.value = value;
		}
		
		public static GmlVar operator +(GmlVar x, GmlVar y)
		{
			if(x.value is real && y.value is real)
				return (real)x.value + (real)y.value;
			else if(x.value is string && y.value is string)
				return (string)x.value + (string)y.value;
			
			throw new ArgumentException("Can't add GmlVars of different types");
		}
		public static GmlVar operator -(GmlVar x, GmlVar y)
		{
			if(x.value is real && y.value is real)
				return (real)x.value-(real)y.value;
				
			throw new ArgumentException("Can't subtract GmlVars of type other than real");
		}
		public static GmlVar operator *(GmlVar x, GmlVar y)
		{
			if(x.value is real && y.value is real)
				return (real)x.value*(real)y.value;
			
			throw new ArgumentException("Can't multiply GmlVars of type other than real");
		}
		public static GmlVar operator /(GmlVar x, GmlVar y)
		{
			if(x.value is real && y.value is real)
				return (real)x.value/(real)y.value;
			
			throw new ArgumentException("Can't divide GmlVars of type other than real");
		}
		public static GmlVar operator %(GmlVar x, GmlVar y)
		{
			if(x.value is real && y.value is real)
				return (real)x.value%(real)y.value;
			
			throw new ArgumentException("Can't do modulo on GmlVars of type other than real");
		}
		public static GmlVar operator &(GmlVar x, GmlVar y)
		{
			if(x.value is real && y.value is real)
				return (real)x.value&(real)y.value;
			
			throw new ArgumentException("Can't do binary AND on GmlVars of type other than real");
		}
		public static GmlVar operator |(GmlVar x, GmlVar y)
		{
			if(x.value is real && y.value is real)
				return (real)x.value|(real)y.value;
			
			throw new ArgumentException("Can't do binary OR on GmlVars of type other than real");
		}
		public static GmlVar operator ^(GmlVar x, GmlVar y)
		{
			if(x.value is real && y.value is real)
				return (real)x.value^(real)y.value;
			
			throw new ArgumentException("Can't do binary XOR on GmlVars of type other than real");
		}
		public static GmlVar operator <<(GmlVar x, int y)
		{
			if(x.value is real)
				return (real)x.value<<(real)y;
			
			throw new ArgumentException("Can't do binary left shift on GmlVars of type other than real");
		}
		public static GmlVar operator >>(GmlVar x, int y)
		{
			if(x.value is real)
				return (real)x.value>>(real)y;
			
			throw new ArgumentException("Can't do binary right shift on GmlVars of type other than real");
		}
		public static GmlVar operator ==(GmlVar x, GmlVar y)
		{
			if(x.value is real && y.value is real)
				return ((real)x.value == (real)y.value);
			else if(x.value is string && y.value is string)
				return ((string)x.value == (string)y.value);
			
			throw new ArgumentException("Can't compare GmlVars of different types");
		}
		public static GmlVar operator ==(bool x, GmlVar y)
		{
			if(y.value is real)
				return (x == (real)y.value);
			
			throw new ArgumentException("Can't compare GmlVars of different types");
		}
		public static GmlVar operator ==(GmlVar x, bool y)
		{
			if(x.value is real)
				return ((real)x.value == y);
			
			throw new ArgumentException("Can't compare GmlVars of different types");
		}
		public static GmlVar operator !=(GmlVar x, GmlVar y)
		{
			if(x.value is real && y.value is real)
				return ((real)x.value != (real)y.value);
			else if(x.value is string && y.value is string)
				return ((string)x.value != (string)y.value);
			
			throw new ArgumentException("Can't compare GmlVars of different types");
		}
		public static GmlVar operator !=(bool x, GmlVar y)
		{
			if(y.value is real)
				return (x != (real)y.value);
			
			throw new ArgumentException("Can't compare GmlVars of different types");
		}
		public static GmlVar operator !=(GmlVar x, bool y)
		{
			if(x.value is real)
				return ((real)x.value != y);
			
			throw new ArgumentException("Can't compare GmlVars of different types");
		}
		public static GmlVar operator >(GmlVar x, GmlVar y)
		{
			if(x.value is real && y.value is real)
				return ((real)x.value > (real)y.value);
			else if(x.value is string && y.value is string)
				return (string.Compare((string)x.value, (string)y.value) > 0);
			
			throw new ArgumentException("Can't compare GmlVars of different types");
		}
		public static GmlVar operator <(GmlVar x, GmlVar y)
		{
			if(x.value is real && y.value is real)
				return ((real)x.value < (real)y.value);
			else if(x.value is string && y.value is string)
				return (string.Compare((string)x.value, (string)y.value) < 0);
			
			throw new ArgumentException("Can't compare GmlVars of different types");
		}
		public static GmlVar operator >=(GmlVar x, GmlVar y)
		{
			if(x.value is real && y.value is real)
				return ((real)x.value >= (real)y.value);
			else if(x.value is string && y.value is string)
				return (string.Compare((string)x.value, (string)y.value) >= 0);
			
			throw new ArgumentException("Can't compare GmlVars of different types");
		}
		public static GmlVar operator <=(GmlVar x, GmlVar y)
		{
			if(x.value is real && y.value is real)
				return ((real)x.value <= (real)y.value);
			else if(x.value is string && y.value is string)
				return (string.Compare((string)x.value, (string)y.value) <= 0);
			
			throw new ArgumentException("Can't compare GmlVars of different types");
		}
		public static GmlVar operator !(GmlVar x)
		{
			if(x.value is real)
				return (!(real)x.value);
			
			throw new ArgumentException("Can't do not operator on GmlVars of type other than real");
		}
		
		public static GmlVar operator +(GmlVar x)
		{
			if(x.value is real)
				return (+(real)x.value);
			
			throw new ArgumentException("Can't do unary plus operator on GmlVars of type other than real");
		}
		
		public static GmlVar operator -(GmlVar x)
		{
			if(x.value is real)
				return (-(real)x.value);
			
			throw new ArgumentException("Can't do unary minus operator on GmlVars of type other than real");
		}
		
		public static implicit operator GmlVar(bool x)
		{
			return new GmlVar(new real(x ? 1 : 0));
		}
		
		public static implicit operator GmlVar(double x)
		{
			return new GmlVar(new real(x));
		}
		
		public static implicit operator GmlVar(real x)
		{
			return new GmlVar(new real(x));
		}
		
		public static implicit operator GmlVar(string x)
		{
			return new GmlVar(x);
		}
		
		public static implicit operator string(GmlVar x)
		{
			return x.ToString();
		}
		
		public static implicit operator bool(GmlVar x)
		{
			if(x.value is real)
				return (bool)(real)x.value;
			
			throw new ArgumentException("Can't convert GmlVars to bool other than real");
		}
		
		public static implicit operator int(GmlVar x)
		{
			if(x.value is real)
				return (int)(real)x.value;
			
			throw new ArgumentException("Can't convert GmlVars to int other than real");
		}
		
		public override string ToString()
		{
			if(value is real)
			{
				return ((real)value).ToString();
			}
			return (string)value;
		}
		
		public static bool operator true(GmlVar x)
		{
			if(x.value is real)
				return (((real)x.value).val > 0);
			
			throw new ArgumentException("Only reals can be used as bool");
		}
		public static bool operator false(GmlVar x)
		{
			if(x.value is real)
				return (((real)x.value).val <= 0);
			
			throw new ArgumentException("Only reals can be used as bool");
			
		}
		
		public override bool Equals(object obj)
		{
			return base.Equals(obj);
		}
		
		public override int GetHashCode()
		{
			return base.GetHashCode();
		}
	}
}
